﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace Home.ArtDB.WinGui
{
    /// <summary>
    /// 
    /// </summary>
    public class StartArgs
    {
        /// <summary></summary>
        public const string STARTARG_STARTUPPATH = "#startuppath";

        /// <summary></summary>
        public const string STARTARGPREFIX_FREE = "#free";

        /// <summary></summary>
        private int _freeArgIndex = 0;

        /// <summary></summary>
        private Dictionary<string, string> _lineStartArgs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        /// <summary></summary>
        private string[] _defaults;

        /// <summary></summary>
        public string StartupApp { get { return _lineStartArgs[STARTARG_STARTUPPATH]; } }

        /// <summary></summary>
        public string StartupPath { get { return Path.GetDirectoryName(_lineStartArgs[STARTARG_STARTUPPATH]); } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="defaults"></param>
        public StartArgs(params string[] defaults)
        {
            _defaults = defaults;

            Reset();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Reset()
        {
            _lineStartArgs.Clear();
            _freeArgIndex = 0;

            //Voreinstellungen initialisieren

            foreach (string defa in _defaults)
            {
                string[] parts = defa.Split('|');
                if (parts.Length > 1)
                    _lineStartArgs.Add(parts[0].ToLower(), parts[1]);
                else
                    _lineStartArgs.Add(parts[0].ToLower(), "");
            }

            //Start Argumente aus Environment einlesen
            DataBind(Environment.GetCommandLineArgs(), true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="argFilePath"></param>
        /// <returns></returns>
        public bool DataBind(Uri argFilePath)
        {
            bool result = File.Exists(argFilePath.LocalPath);

            if (result)
            {
                string[] args = File.ReadAllLines(argFilePath.LocalPath);

                AddFreeArgs(args);

                DataBind(args, false);
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        public void DataBind()
        {
            AddFreeArgs(Environment.GetCommandLineArgs());

            DataBind(Environment.GetCommandLineArgs(), true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        public void DataBind(string[] args)
        {
            AddFreeArgs(args);

            DataBind(args, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        private void AddFreeArgs(string[] args)
        {
            foreach (string freeArg in args.Where(item => !item.Trim().StartsWith("/")))
            {
                if (!_lineStartArgs.Any(item => item.Key.StartsWith(STARTARGPREFIX_FREE) && item.Value.Equals(freeArg)))
                {
                    _lineStartArgs.Add(STARTARGPREFIX_FREE + (_freeArgIndex++).ToString(), freeArg);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        /// <param name="initial"></param>
        private void DataBind(string[] args, bool initial)
        {
            //Parameter zusammenführen um die Leerzeichen in der Parameter zu erhalten.
            //Nur ein Leerzeichen wird unterstützt.
            string argstring = "";
            foreach (string arg in args)
            {
                if (initial && !arg.StartsWith("/") && argstring.Equals(string.Empty))
                {
                    argstring += string.Format("/{0}=\"{1}\" ", STARTARG_STARTUPPATH, arg);
                }
                else if (initial && !arg.StartsWith("/"))
                {
                    argstring += string.Format("/{0}{1}=\"{2}\" ", STARTARGPREFIX_FREE, _freeArgIndex++, arg);
                }
                else if (arg.StartsWith("/") && arg.IndexOf('=').Equals(-1))
                {
                    argstring += string.Format("{0}=\"\" ", arg.Trim());
                }
                else
                {
                    string[] parts = arg.Split(new char[] { '=' }, 2);
                    string name = parts[0].Trim();
                    string value = parts[1].Trim();

                    argstring += string.Format("{0}={1}{2}{3} ", name, (value.StartsWith("\"") ? "" : "\""), value, (value.EndsWith("\"") ? "" : "\""));
                }
            }

            string str = argstring;
            while (str.Length > 0)
            {
                int startIndex = str.IndexOf("/");
                if (startIndex.Equals(-1))
                    break;

                int likeIndex = str.IndexOf("=", startIndex);

                string name = str.Substring(startIndex, likeIndex - startIndex).TrimStart('/').Trim();

                str = str.Remove(0, likeIndex).TrimStart('=');

                string value = str;

                int endIndex = str.IndexOf("\" /");

                int quotaCount = !endIndex.Equals(-1) ? str.Substring(0, endIndex).Cast<char>().Where(item => item.Equals('\"')).Count() : 0;

                //Nach kompletes Parameter suchen bis Anzahl der Anführungszeichen gerade ist (ungerade weil inkl. das erste Anführungszeichen)
                while (!endIndex.Equals(-1) && !(quotaCount % 2).Equals(1))
                {
                    endIndex = str.IndexOf("\" /", endIndex + 1);
                    if (!endIndex.Equals(-1))
                    {
                        quotaCount = str.Substring(0, endIndex).Cast<char>().Where(item => item.Equals('\"')).Count();
                        endIndex++;
                    }
                }

                if (!endIndex.Equals(-1))
                {
                    value = str.Substring(0, endIndex);
                    str = str.Remove(0, endIndex);
                }
                else
                {
                    str = "";
                }

                value = value.Trim();
                value = (value.EndsWith("\"") ? value.Substring(0, value.Length - 1) : value).TrimStart('\"');

                //Argument hinzufügen
                if (!_lineStartArgs.ContainsKey(name))
                {
                    _lineStartArgs.Add(name, value);
                }
                else
                {
                    _lineStartArgs[name] = value;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string Get(string key, string defaultvalue="")
        {
            return _lineStartArgs.ContainsKey(key) ? _lineStartArgs[key] : defaultvalue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultvalue"></param>
        /// <returns></returns>
        public bool Get(string key, bool defaultvalue)
        {
            return _lineStartArgs.ContainsKey(key) ? ToBool(_lineStartArgs[key], defaultvalue) : defaultvalue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultvalue"></param>
        /// <returns></returns>
        public int Get(string key, int defaultvalue)
        {
            return _lineStartArgs.ContainsKey(key) ? ToInt(_lineStartArgs[key], defaultvalue) : defaultvalue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllFree()
        {
            return _lineStartArgs.Where(item => item.Key.StartsWith(STARTARGPREFIX_FREE)).Select(item => item.Value).ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        private bool ToBool(string str, bool defaultValue)
        {
            bool result = defaultValue;

            if (!Boolean.TryParse(str, out result))
            {
                result = defaultValue;
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        private int ToInt(string str, int defaultValue)
        {
            if (string.IsNullOrEmpty(str))
                return defaultValue;

            int result = defaultValue;

            if (str != null && !str.Trim().Equals(string.Empty))
            {
                str = str.Split(new char[] { ',', '.' }, StringSplitOptions.RemoveEmptyEntries)[0];

                if (!int.TryParse(str, out result))
                {
                    result = defaultValue;
                }
            }

            return result;
        }
    }
}
